#!/usr/bin/python3
# -*- coding:utf-8 -*-
"""
@File: BasicCommonSqlMethod.py
@Author: lijk34925 
@Date: 2024/6/3 15:53
@desc: 请补充本模块功能说明
"""
import os.path
import re

from qturboframe.lib.webdriver import SeleniumError

from AmlScripts import blade_variable
from AmlScripts.BasicFunction.ActSqlMethod import check_response, get_sql_text
from AmlScripts.BasicFunction.common_test_prepare import test_db_link
from AmlScripts.BasicFunction.common_test_prepare import sql_handle_class

from BladeFerm.Lib.Common import logger, data_processing
from BladeFerm.databases import DB_APP


@data_processing
def act_sql_and_check(input_data=None, ui_expect=None):
    """
    执行sql语句（select）并进行断言的用例，支持根据环境切换到各类信创数据库去执行
    :param input_data:
        - sql: 固定语句
    :param ui_expect:
        - more： 最小期望行，大于0进行检查
        - rows: 行数，默认-1不检查，大于0进行检查
        - other：select 返回的
    :return:
    """
    def __can_convert_to_number(obj):
        try:
            float(obj)  # 尝试转换为浮点数
            return True
        except ValueError:
            return False
    env = blade_variable.get_variable('varg_db_type')
    min_row = int(ui_expect.pop('more', -1))
    rows = int(ui_expect.pop('rows', -1))
    sql_text = input_data.get("sql", "select * from dual")
    sql_text = sql_text.upper()
    logger.debug(f"env: {env}, min_row: {min_row}, rows: {rows}, input_data: {input_data}, ui_expect: {ui_expect}")
    result_list = DB_APP.run_one_sql(sql_text)
    if not re.match("select", sql_text, re.I):
        logger.warning("非 select 语句，不进行断言！")
        return True
    if 0 <= min_row <= len(result_list):
        logger.info("测试结果符合期望，不少于 {} 行".format(min_row))
        return True
    elif min_row > len(result_list):
        err = f"sql 结果不满足最小期望行 {min_row}"
        raise SeleniumError(err)
    else:
        if result_list:
            if 0 < rows != len(result_list):
                err = f'sql 结果返回行数不符合期望! 实际行数: {len(result_list)}， 期望行数：{rows}'
                logger.error(err)
                raise SeleniumError(err)
            for index, unit in enumerate(result_list):
                for k, v in ui_expect.items():
                    exp_key = k.upper()
                    real_value = unit[exp_key]
                    check_flag = False
                    if (__can_convert_to_number(real_value)
                            and __can_convert_to_number(v)
                            and abs(float(real_value) - float(v)) < 0.1):
                        check_flag = True
                    elif re.search(v, real_value, re.I):
                        check_flag = True
                    if check_flag:
                        logger.info(f"检查第 {index} 行结果 {real_value} 符合测试期望值 {v}。")
                    else:
                        err = f'sql 的实际结果：{real_value}不符合期望结果：{v}，断言失败！'
                        logger.error(err)
                        raise SeleniumError(err)
        elif len(result_list) == 0 and rows == 0:
            pass_info = f'sql result error! real rows: {len(result_list)}'
            logger.info(pass_info)
        elif len(result_list) == 0 and len(list(ui_expect.keys())) > 0:
            err = f'sql 结果为空，无法进一步断言！'
            logger.error(err)
            raise SeleniumError(err)
        else:
            warn = 'sql 结果未空，期望也为空！不进行断言！'
            logger.warn(warn)


@data_processing
def export_fund_test_data(input_data=None, ui_expect=None):
    sc_path = input_data.get("SQL目录", "数据预埋/系统流程/00基金测试数据")
    env_name = input_data.get("env", None)
    if env_name is None:
        env_name = blade_variable.get_variable('varg_db_type')
    root_path = blade_variable.get_variable('varu_CurrentPath')
    if root_path and root_path != 'AGENT_EMPTY':
        sql_path = os.path.join(root_path, sc_path)
    else:
        sql_path = os.path.join("E:\AutoTest\Project\金融反洗钱项目\web应用", sc_path)
    logger.info(f"sql_path: {sql_path}")
    sql_list = os.listdir(sql_path)
    for sql_file in sql_list:
        sql_file_path = os.path.join(sql_path, sql_file)
        if os.path.isfile(sql_file_path):
            sql_handle_class(env_name, sql_file_path)


@test_db_link
@data_processing
def act_sql(input_data=None, ui_expect=None):
    """
    执行sql语句，并断言结果
    Args:
        input_data:  *代表必填项， -代表选填
            场景1：读取sql文件中的sql所需参数
                * 文件名: sql文件的名称
                - encoding: 读取sql文件的编码格式，默认用 utf-8
            场景2：读取输入参数的sql所需的参数
                * SQL语句: sql语句，多个用 ; 分割
            场景3：读取的sql中的值存在变量的，根据入参进行变量替换
                * SQL语句: sql语句，多个用 ; 分割
                - key1: value1
            场景4：拼接sql所需的参数
                * table_name: 表名称, 必填参数
                - sql_json_path： insert所需的初始数据的路径.非必填参数，如果不填，根据表名读取
                * sql_type: sql的类型，eg：insert，Delete, UPDATE，select
                - select_keys: select所需的key，eg：k1,k2,k3 ; count(*) as N1
                * key  : 字段名称和字段值，用于更新insert ... into，update ... where之间的值
                * key:,:key,key|,|key : where条件的要填的值，字段前或后，添加 | 或 ：进行区分
                - logic：where条件字段的拼接关系，and 或 or；缺省值：and
            场景5：脚本内部断言所需的参数
                - 是否内部断言: 缺省值：True
        ui_expect:
            断言场景1：断言实际返回结果的值是否是期望的 k=v
                - k1：v1    # v 若以 ‘|re’ 结束时，采用正则匹配方式进行断言
            断言场景2：根据期望的sql执行返回的结果，与实际的执行sql返回的结果进行比对，断言不同2张表中通一字段是否相同
                - SQL1: 'select * from dual;'

    Returns:

    """
    # 1.分析并获取sql
    sql_lines = get_sql_text(input_data, ui_expect)
    # 2.执行sql
    sql_response = DB_APP.get_run_sql_result(sql_lines)
    # 3.断言
    input_data['act_sql_response'] = sql_response
    ui_expect = ui_expect if MS.ui_expect is None else MS.ui_expect
    check_result = check_response(input_data, ui_expect)
    return sql_response, check_result


@data_processing
def assert_response(input_data=None, ui_expect=None):
    """
    同 check_response 方法，但是仅用于单独调用的断言。此时需执行装饰器步骤，处理输入参数格式
    Args:
        input_data:
        ui_expect:

    Returns:

    """
    return check_response(input_data, ui_expect)


@data_processing
def check_risk_lever(input_data=None, ui_expect=None):
    """
    数据预处理，
    Args:
        data:
        data_exp: ‘2233’，‘2552’   555

    Returns:

    """
    client_id = input_data.get('client_id')
    client_ids = ', '.join([f"'{unit}'" for unit in client_id.split(',')])
    rules_no = input_data.get('rules_no')
    sql_lines = [f"select SCORE_VALUE as SV from hsamlrc.amlrc_riskrules WHERE inner_client_id in ({client_ids}) and rules_no = '{rules_no}'"]
    logger.info(f'SQL语句:{sql_lines}')
    sql_response = DB_APP.get_run_sql_result(sql_lines)
    input_data['act_sql_response'] = sql_response
    check_response(input_data=input_data, ui_expect=ui_expect)